﻿using Agile.Infra.Core.Agile.Extensions;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;

namespace Agile.Infra.WeiXin;

public partial class AppletService
{
    public async Task<string> GetAccessTokenAsync()
    {
        var appID = _appleOptions.AppId;
        // 尝试从缓存获取
        if (_memoryCache.TryGetValue(GetAccessTokenCacheKey(appID), out string accessToken))
        {
            return accessToken;
        }

        // 创建针对当前code的信号量（防止重复请求）
        var semaphore = _codeLocks.GetOrAdd(appID, _ => new SemaphoreSlim(1, 1));

        await semaphore.WaitAsync();
        try
        {
            // 双重检查缓存
            if (_memoryCache.TryGetValue(GetAccessTokenCacheKey(appID), out accessToken))
            {
                return accessToken;
            }
             
            var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"{_appleOptions.ServerUrl}/cgi-bin/token?appid={appID}&secret={_appleOptions.Secret}&grant_type=client_credential");
           
            var response = await HttpRequestAsync(appID, httpRequestMessage);

            var result = response.ToJsonObject<AccessTokenModel>();

            // 仅当获取到有效结果时缓存
            if (!string.IsNullOrEmpty(result?.access_token))
            {
                _memoryCache.Set(GetAccessTokenCacheKey(appID), result.access_token, TimeSpan.FromSeconds(result.expires_in - 10));
            }
            return result.access_token;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "小程序获取AccessToken");
        }
        finally
        {
            semaphore.Release();
            _codeLocks.TryRemove(appID, out _); // 清理信号量
        }
        return null;
    }


    #region 响应实体

    internal class AccessTokenModel
    {
        /// <summary> 获取到的凭证 </summary>
        public string access_token { get; set; }

        /// <summary> 凭证有效时间，单位：秒。目前是7200秒之内的值。 </summary> 
        public int expires_in { get; set; }
    }

    #endregion
}
